#![allow(non_snake_case)]
use chrono::{Datelike, Local, NaiveDate, NaiveTime};
use icondata as i;
use leptos::prelude::*;
use leptos_icons::*;
use serde_json::Value;
use shq_common::prelude::{edit_props::EditProps, options::Options, ControlType, DataType, Size};
use std::collections::HashSet;
use thaw_utils::{ArcOneCallback, BoxOneCallback};

use crate::{
    validate_value, AutoSearch, Checkbox, CheckboxGroup, CheckboxItem, DatePicker, EditColValues,
    Input, InputNumber, InputPrefix, InputSuffix, MonthPicker, MultiSelect, Popover,
    PopoverTrigger, QuarterPicker, RadioGroup, RadioItem, Select, SelectOption, TableState,
    TextArea, TimePicker, TreeItems, TreeSelect, YearPicker,
};
#[component]
pub fn EditControl(
    col_name: StoredValue<String>,
    edit_props: StoredValue<EditProps>,
    data_type: DataType,
    #[prop(optional, into)] value: Option<Value>,
    #[prop(default=None, into)] value_label: Option<String>,
    #[prop(optional, into)] disabled: bool,
    #[prop(optional, into)] on_change: Option<ArcOneCallback<Value>>,
    #[prop(optional, into)] size: Size,
    #[prop(optional, into)] label: MaybeProp<String>,
    #[prop(optional, into)] err_msg: MaybeProp<String>,
    #[prop(default=true.into(), into)] border: MaybeProp<bool>,
    #[prop(optional, into)] inner_max_width: u32,
    #[prop(optional, into)] is_init_focus: bool,
) -> impl IntoView {
    let table_state = use_context::<ReadSignal<TableState>>();
    let edit_col_vals = use_context::<ReadSignal<EditColValues>>();
    let range = edit_props.with_value(|ep| ep.range_rule.clone());
    let multiple = edit_props.with_value(|ep| ep.multiple);
    let opt_conf = StoredValue::new(edit_props.with_value(|ep| ep.options.clone()));
    let cont_type = edit_props.with_value(|ep| ep.control_type);
    let init_value = if cont_type == ControlType::Search {
        if let Some(v) = value_label {
            Value::String(v)
        } else {
            Value::Null
        }
    } else {
        if let Some(v) = value {
            v
        } else if let Some(l) = value_label {
            if cont_type == ControlType::Search {
                Value::String(l)
            } else {
                if let Some(v) = get_select_option_value(opt_conf, &l) {
                    Value::String(v)
                } else {
                    Value::Null
                }
            }
        } else {
            Value::Null
        }
    };
    let value = StoredValue::new(init_value);
    let placeholder = edit_props.with_value(|ep| ep.placeholder.clone());
    let required = edit_props.with_value(|ep| ep.required);
    let label_view = move || {
        if let Some(label) = label.get() {
            view! { <span class="text-neutral min-w-6 text-nowrap text-ellipsis">{label}</span> }
                .into()
        } else {
            None
        }
    };
    let set_value = move |val: Value, label: Option<String>| {
        if let Some(edit_col_vals) = edit_col_vals {
            let table_state = table_state.unwrap();
            let curr_cell = table_state.with_untracked(|ts| ts.curr_cell().get_untracked());
            if let Some((row_index, _)) = curr_cell {
                if let Some(msg) = validate_value(data_type.clone(), required, range.clone(), &val)
                {
                    edit_col_vals.with_untracked(|ecv| {
                        col_name.with_value(|cname| {
                            ecv.set_error_msg(row_index, cname, Some(msg));
                        });
                    });
                } else {
                    edit_col_vals.with_untracked(|ecv| {
                        col_name.with_value(|cname| {
                            ecv.set_value(row_index, cname, val);
                            ecv.set_title(row_index, cname, label);
                            ecv.set_error_msg(row_index, cname, None);
                        });
                    });
                }
            }
        }
    };
    let err_msg_view = move || {
        if let Some(msg) = err_msg.get() {
            view! { <Popover>
                <PopoverTrigger slot>
                    <div><Icon icon=i::BiErrorCircleRegular style="color: var(--color-red-500);"/></div>
                </PopoverTrigger>
                {msg}
            </Popover>}
            .into()
        } else {
            None
        }
    };
    match cont_type {
        ControlType::TextInput | ControlType::Textarea => {
            let sv = value.with_value(|v| {
                if *v == Value::Null {
                    None
                } else {
                    Some(json_val_to_string(v))
                }
            });
            let allow_value = ArcOneCallback::new(move |v: String| {
                if v.is_empty() {
                    return true;
                }
                str_in_range(&v, range)
            });
            let on_change = move |v: Option<String>| {
                let jv = v.map(|sv| Value::String(sv)).unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    set_value(jv, None);
                }
            };
            either_of::EitherOf16::A(if cont_type == ControlType::TextInput {
                either_of::Either::Left(view! {
                    <Input value=sv size disabled allow_value placeholder on_change border inner_max_width is_init_focus>
                        <InputPrefix slot>
                            {label_view}
                        </InputPrefix>
                        <InputSuffix slot>
                            {err_msg_view}
                        </InputSuffix>
                    </Input>
                })
            } else {
                either_of::Either::Right(view! {
                    <TextArea value=sv size disabled placeholder on_change is_init_focus/>
                })
            })
        }
        ControlType::IntegerInput => {
            let sv = value.with_value(|v| {
                if *v == Value::Null {
                    None
                } else {
                    Some(v.as_i64().unwrap_or(0))
                }
            });
            let rg = range.map(|r| (r.0 as i64, r.1 as i64));
            let on_change = ArcOneCallback::new(move |v: Option<i64>| {
                let jv = v.map(|iv| Value::from(iv)).unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    set_value(jv, None);
                }
            });
            either_of::EitherOf16::B(view! {
                <InputNumber value=sv step=1 size disabled placeholder range=rg on_change border inner_max_width is_init_focus>
                    <InputPrefix slot>
                        {label_view}
                    </InputPrefix>
                    <InputSuffix slot>
                        {err_msg_view}
                    </InputSuffix>
                </InputNumber>
            })
        }
        ControlType::DecimalInput => {
            let sv = value.with_value(|v| {
                if *v == Value::Null {
                    None
                } else {
                    Some(v.as_f64().unwrap_or(0.0))
                }
            });
            let rg = range.map(|r| (r.0 as f64, r.1 as f64));
            let on_change = move |v: Option<f64>| {
                let jv = v.map(|fv| Value::from(fv)).unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    set_value(jv, None);
                }
            };
            either_of::EitherOf16::C(view! {
                <InputNumber value=sv step=0.1 size disabled placeholder range=rg on_change border inner_max_width is_init_focus>
                    <InputPrefix slot>
                        {label_view}
                    </InputPrefix>
                    <InputSuffix slot>
                        {err_msg_view}
                    </InputSuffix>
                </InputNumber>
            })
        }
        ControlType::AlphaInput | ControlType::AlphanumInput => {
            let sv = value.with_value(|v| {
                if *v == Value::Null {
                    None
                } else {
                    Some(json_val_to_string(v))
                }
            });
            let allow_value = ArcOneCallback::new(move |v: String| {
                if v.is_empty() {
                    return true;
                }
                let has_num = cont_type == ControlType::AlphanumInput;
                let is_ok = v.chars().all(|c| {
                    if has_num {
                        c.is_ascii_alphanumeric()
                    } else {
                        c.is_ascii_alphabetic()
                    }
                });
                if !is_ok {
                    return false;
                }
                str_in_range(&v, range)
            });
            let on_change = move |v: Option<String>| {
                let jv = v.map(|sv| Value::String(sv)).unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    set_value(jv, None);
                }
            };
            either_of::EitherOf16::D(if cont_type == ControlType::TextInput {
                either_of::Either::Left(view! {
                <Input value=sv allow_value size disabled placeholder on_change border inner_max_width is_init_focus>
                    <InputPrefix slot>
                        {label_view}
                    </InputPrefix>
                    <InputSuffix slot>
                        {err_msg_view}
                    </InputSuffix>
                </Input>})
            } else {
                either_of::Either::Right(view! {
                    <Input value=sv allow_value size disabled placeholder on_change border inner_max_width is_init_focus>
                        <InputPrefix slot>
                            {label_view}
                        </InputPrefix>
                        <InputSuffix slot>
                            {err_msg_view}
                        </InputSuffix>
                    </Input>
                })
            })
        }
        ControlType::Year => {
            let iv = value.with_value(|v| {
                if *v == Value::Null {
                    None
                } else {
                    let v = if let Value::String(sv) = v {
                        sv.parse::<i32>().ok()
                    } else if v.is_f64() {
                        None
                    } else if v.is_u64() {
                        v.as_u64().map(|v| v as i32)
                    } else if v.is_i64() {
                        v.as_i64().map(|v| v as i32)
                    } else {
                        None
                    }
                    .unwrap_or(Local::now().year());
                    Some(v)
                }
            });
            let on_change = move |v: Option<i32>| {
                let jv = v.map(|iv| Value::from(iv)).unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    set_value(jv, None);
                }
            };
            either_of::EitherOf16::E(view! {
                <YearPicker value=iv size disabled placeholder on_change border inner_max_width is_init_focus>
                    <InputPrefix slot>
                        {label_view}
                    </InputPrefix>
                    <InputSuffix slot>
                        {err_msg_view}
                    </InputSuffix>
                </YearPicker>
            })
        }
        ControlType::Quarter => {
            let iv = value.with_value(|v| {
                if *v == Value::Null {
                    None
                } else {
                    let v = if let Value::String(sv) = v {
                        sv.replace('Q', "").parse::<i32>().ok()
                    } else if v.is_f64() {
                        None
                    } else if v.is_u64() {
                        v.as_u64().map(|v| v as i32)
                    } else if v.is_i64() {
                        v.as_i64().map(|v| v as i32)
                    } else {
                        None
                    }
                    .unwrap_or(Local::now().year());
                    Some(v)
                }
            });
            let on_change = move |v: Option<i32>| {
                let jv = v.map(|iv| Value::from(iv)).unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    set_value(jv, None);
                }
            };
            either_of::EitherOf16::F(view! {
                <QuarterPicker value=iv size disabled placeholder on_change border inner_max_width is_init_focus>
                    <InputPrefix slot>
                        {label_view}
                    </InputPrefix>
                    <InputSuffix slot>
                        {err_msg_view}
                    </InputSuffix>
                </QuarterPicker>
            })
        }
        ControlType::Month => {
            let iv = value.with_value(|v| match v {
                Value::Null => None,
                Value::String(sv) => {
                    let sv = sv.as_str();
                    sv.parse::<i32>().ok()
                }
                Value::Number(sv) => {
                    if sv.is_f64() {
                        None
                    } else if sv.is_u64() {
                        sv.as_u64().map(|v| v as i32)
                    } else if sv.is_i64() {
                        sv.as_i64().map(|v| v as i32)
                    } else {
                        None
                    }
                }
                _ => None,
            });
            let on_change = move |v: Option<i32>| {
                let jv = v.map(|iv| Value::from(iv)).unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    set_value(jv, None);
                }
            };
            either_of::EitherOf16::G(view! {
                <MonthPicker value=iv size disabled placeholder on_change border inner_max_width is_init_focus>
                    <InputPrefix slot>
                        {label_view}
                    </InputPrefix>
                    <InputSuffix slot>
                        {err_msg_view}
                    </InputSuffix>
                </MonthPicker>
            })
        }
        ControlType::Date => {
            let init_val = value.with_value(|v| {
                if v == &Value::Null {
                    return None;
                }
                let sv = v.as_str().unwrap_or("");
                let dv = if sv.contains('-') {
                    NaiveDate::parse_from_str(sv, "%Y-%m-%d")
                        .unwrap_or(Local::now().naive_local().date())
                } else {
                    NaiveDate::parse_from_str(sv, "%Y%m%d")
                        .unwrap_or(Local::now().naive_local().date())
                };
                Some(dv)
            });
            let on_change = move |v: Option<String>| {
                let jv = v.map(|iv| Value::from(iv)).unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    set_value(jv, None);
                }
            };
            either_of::EitherOf16::H(view! {
                <DatePicker value=init_val size disabled placeholder on_change border inner_max_width is_init_focus>
                    <InputPrefix slot>
                        {label_view}
                    </InputPrefix>
                    <InputSuffix slot>
                        {err_msg_view}
                    </InputSuffix>
                </DatePicker>
            })
        }
        ControlType::Time => {
            let init_val = value.with_value(|v| {
                if v == &Value::Null {
                    return None;
                }
                let sv = v.to_string();
                let tv = NaiveTime::parse_from_str(sv.as_str(), "%H:%M:%S")
                    .unwrap_or(NaiveTime::default());
                Some(tv)
            });
            let on_change = move |v: Option<String>| {
                let jv = v.map(|iv| Value::from(iv)).unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    set_value(jv, None);
                }
            };
            either_of::EitherOf16::I(view! {
                <TimePicker value=init_val size disabled placeholder on_change inner_max_width is_init_focus>
                    <InputPrefix slot>
                        {label_view}
                    </InputPrefix>
                    <InputSuffix slot>
                        {err_msg_view}
                    </InputSuffix>
                </TimePicker>
            })
        }
        ControlType::Datetime => {
            let init_val = value.with_value(|v| {
                if v == &Value::Null {
                    return None;
                }
                let sv = v.to_string();
                let dv = if sv.contains('-') {
                    NaiveDate::parse_from_str(sv.as_str(), "%Y-%m-%d %H:%M:%S")
                        .unwrap_or(NaiveDate::default())
                } else {
                    NaiveDate::parse_from_str(sv.as_str(), "%Y%m%d %H%M%S")
                        .unwrap_or(NaiveDate::default())
                };
                Some(dv)
            });
            let on_change = move |v: Option<String>| {
                let jv = v.map(|iv| Value::from(iv)).unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    set_value(jv, None);
                }
            };
            either_of::EitherOf16::J(view! {
                <DatePicker value=init_val size disabled placeholder on_change border inner_max_width is_init_focus>
                    <InputPrefix slot>
                        {label_view}
                    </InputPrefix>
                    <InputSuffix slot>
                        {err_msg_view}
                    </InputSuffix>
                </DatePicker>
            })
        }
        ControlType::Select => {
            let options: Vec<SelectOption<String>> = get_select_options(opt_conf);
            let sel_view = if multiple {
                let values = value.with_value(|v| get_multi_values(v));
                let on_change = move |vals: Vec<String>| {
                    let sv = if vals.is_empty() {
                        Value::Null
                    } else {
                        let val2 = vals.join("|");
                        Value::from(val2)
                    };
                    if let Some(on_change) = on_change.as_ref() {
                        on_change(sv);
                    } else {
                        let labels = get_multi_select_option_labels(opt_conf, &vals);
                        set_value(sv, labels);
                    }
                };
                either_of::Either::Left(view! {
                    <MultiSelect values options size disabled placeholder on_change border inner_max_width is_init_focus>
                        <InputPrefix slot>
                            {label_view}
                        </InputPrefix>
                        <InputSuffix slot>
                            {err_msg_view}
                        </InputSuffix>
                    </MultiSelect>
                })
            } else {
                let init_val = value.with_value(|v| {
                    if *v == Value::Null {
                        None
                    } else {
                        Some(json_val_to_string(v))
                    }
                });
                let on_change = move |v: Option<String>| {
                    let jv = v
                        .as_ref()
                        .map(|v| Value::from(v.clone()))
                        .unwrap_or(Value::Null);
                    if let Some(on_change) = on_change.as_ref() {
                        on_change(jv);
                    } else {
                        let label = get_select_option_label(opt_conf, v.as_deref());
                        set_value(jv, label);
                    }
                };
                either_of::Either::Right(view! {
                    <Select value=init_val options size disabled placeholder on_change border inner_max_width is_init_focus>
                        <InputPrefix slot>
                            {label_view}
                        </InputPrefix>
                        <InputSuffix slot>
                            {err_msg_view}
                        </InputSuffix>
                    </Select>
                })
            };
            either_of::EitherOf16::K(sel_view)
        }
        ControlType::TreeSelect => {
            let init_val = value.with_value(|v| {
                if *v == Value::Null {
                    None
                } else {
                    Some(json_val_to_string(v))
                }
            });
            let on_change = move |v: Option<String>| {
                let jv = v.clone().map(|sv| Value::from(sv)).unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    let label = get_select_option_label(opt_conf, v.as_deref());
                    set_value(jv, label);
                }
            };
            let tree_items = opt_conf.with_value(|opt_conf| {
                opt_conf
                    .as_ref()
                    .and_then(|opts| Some(TreeItems::from_options(opts)))
                    .unwrap_or_default()
            });
            either_of::EitherOf16::L(view! {
                <TreeSelect value=init_val size disabled tree_items=StoredValue::new(tree_items) placeholder on_change border inner_max_width is_init_focus>
                    <InputPrefix slot>
                        {label_view}
                    </InputPrefix>
                    <InputSuffix slot>
                        {err_msg_view}
                    </InputSuffix>
                </TreeSelect>
            })
        }
        ControlType::Checkbox => {
            let init_val = value.with_value(|v| v.as_bool().unwrap_or(false));
            let on_change = move |v: bool| {
                let jv = Value::from(v);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    let label =
                        get_select_option_label(opt_conf, if v { Some("true") } else { None });
                    set_value(jv, label);
                }
            };
            either_of::EitherOf16::M(view! {
                <Checkbox value=init_val size disabled on_change>
                    {label_view}
                </Checkbox>
            })
        }
        ControlType::CheckboxGroup => {
            let values = value.with_value(|v| get_multi_values(v));
            let lables = get_multi_select_option_labels(opt_conf, &values);
            let init_vals: HashSet<String> = HashSet::from_iter(values.into_iter());
            let on_change = move |vals: HashSet<String>| {
                let sv = if vals.is_empty() {
                    Value::Null
                } else {
                    let val2 = vals.into_iter().collect::<Vec<String>>();
                    Value::from(val2.join("|"))
                };
                if let Some(on_change) = on_change.as_ref() {
                    on_change(sv.clone());
                } else {
                    set_value(sv, lables.clone());
                }
            };
            let children = {
                let opts = get_select_options(opt_conf);
                if !opts.is_empty() {
                    let c = opts
                        .into_iter()
                        .map(|v| {
                            let key = v.value.clone();
                            let label = v.label.clone();
                            view! {<CheckboxItem key label size disabled/>}
                        })
                        .collect_view();
                    Some(c)
                } else {
                    None
                }
            };
            either_of::EitherOf16::N(view! {
                <CheckboxGroup value=init_vals on_change>
                    {children}
                </CheckboxGroup>
            })
        }
        ControlType::RadioGroup => {
            let init_val = value.with_value(|v| {
                if *v == Value::Null {
                    None
                } else {
                    Some(json_val_to_string(v))
                }
            });
            let on_change = move |v: Option<String>| {
                let jv = v.clone().map(|sv| Value::from(sv)).unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    let label = get_select_option_label(opt_conf, v.as_deref());
                    set_value(jv, label);
                }
            };
            let children = {
                let opts = get_select_options(opt_conf);
                if !opts.is_empty() {
                    let c = opts
                        .into_iter()
                        .map(|v| {
                            let key = v.value;
                            let label = v.label;
                            view! {<RadioItem key size disabled>{label}</RadioItem>}
                        })
                        .collect_view();
                    Some(c)
                } else {
                    None
                }
            };
            either_of::EitherOf16::O(view! {
                <RadioGroup name="and_or" value=init_val on_change>
                    {children}
                </RadioGroup>
            })
        }
        ControlType::Search => {
            let init_val = value.with_value(|v| {
                if v == &Value::Null {
                    None
                } else {
                    Some(json_val_to_string(v))
                }
            });
            let on_change_with_label = ArcOneCallback::new(move |v: Option<(String, String)>| {
                let jv = v
                    .as_ref()
                    .map(|(v, _l)| Value::from(v.clone()))
                    .unwrap_or(Value::Null);
                if let Some(on_change) = on_change.as_ref() {
                    on_change(jv);
                } else {
                    let l = v.map(|(_v, l)| Some(l)).unwrap_or(None);
                    set_value(jv, l);
                }
            });
            let fetch_params = opt_conf
                .with_value(|opt_conf| {
                    opt_conf.as_ref().and_then(|opts| {
                        if let Options::Fetch(fetch_params) = opts {
                            Some(fetch_params.clone())
                        } else {
                            None
                        }
                    })
                })
                .unwrap_or_else(|| {
                    panic!("Search必须提供fetch_params");
                });
            either_of::EitherOf16::P(view! {
                <AutoSearch value=init_val fetch_params=StoredValue::new(fetch_params) size disabled placeholder on_change_with_label label err_msg border inner_max_width is_init_focus/>
            })
        }
    }
}

fn str_in_range(val: &str, range: Option<(isize, isize)>) -> bool {
    if let Some((_min, max)) = range {
        let l = val.chars().count() as isize;
        let max2 = if max < 0 { 0 } else { max };
        if max2 == 0 {
            return true;
        }
        if l > max2 {
            return false;
        }
    }
    true
}
pub fn json_val_to_string(val: &Value) -> String {
    match val {
        Value::Bool(b) => b.to_string(),
        Value::Number(n) => n.to_string(),
        Value::String(s) => s.to_owned(),
        Value::Null => "".to_string(),
        Value::Object(obj) => format!("{:?}", obj),
        Value::Array(arr) => format!("{:?}", arr),
    }
}

fn get_select_options(opt_conf: StoredValue<Option<Options>>) -> Vec<SelectOption<String>> {
    opt_conf.with_value(|opt_conf| {
        if let Some(opts) = opt_conf {
            match opts {
                Options::Array(items) => items
                    .iter()
                    .map(|opt| SelectOption::new(opt, opt.to_string()))
                    .collect::<Vec<SelectOption<_>>>(),
                Options::Map(kv_items) => kv_items
                    .iter()
                    .map(|kv| SelectOption::new(kv.label.as_str(), kv.value.to_string()))
                    .collect::<Vec<SelectOption<_>>>(),
                Options::Tree(tree_nodes) => tree_nodes
                    .iter()
                    .map(|node| SelectOption::new(node.title.as_str(), node.key.to_string()))
                    .collect::<Vec<SelectOption<_>>>(),
                Options::Fetch(_fetch_params) => vec![],
            }
        } else {
            vec![]
        }
    })
}

fn get_select_option_value(opt_conf: StoredValue<Option<Options>>, label: &str) -> Option<String> {
    opt_conf.with_value(|opt_conf| {
        if let Some(opts) = opt_conf {
            match opts {
                Options::Array(items) => items
                    .iter()
                    .find(|opt| opt == &&label)
                    .map(|opt| opt.to_string()),
                Options::Map(kv_items) => kv_items
                    .iter()
                    .find(|kv| kv.label == label)
                    .map(|kv| kv.value.clone()),
                Options::Tree(tree_nodes) => tree_nodes
                    .iter()
                    .find(|node| node.title == label)
                    .map(|node| node.key.clone()),
                Options::Fetch(_fetch_params) => None,
            }
        } else {
            None
        }
    })
}

fn get_select_option_label(
    opt_conf: StoredValue<Option<Options>>,
    value: Option<&str>,
) -> Option<String> {
    if value.is_none() {
        return None;
    }
    let value = value.unwrap();
    opt_conf.with_value(|opt_conf| {
        if let Some(opts) = opt_conf {
            match opts {
                Options::Array(items) => items
                    .iter()
                    .find(|opt| opt == &&value)
                    .map(|opt| opt.to_string()),
                Options::Map(kv_items) => kv_items
                    .iter()
                    .find(|kv| kv.value == value)
                    .map(|kv| kv.label.clone()),
                Options::Tree(tree_nodes) => tree_nodes
                    .iter()
                    .find(|node| node.key == value)
                    .map(|node| node.title.clone()),
                Options::Fetch(_fetch_params) => None,
            }
        } else {
            None
        }
    })
}

fn get_multi_select_option_labels(
    opt_conf: StoredValue<Option<Options>>,
    values: &[String],
) -> Option<String> {
    if values.is_empty() {
        return None;
    }
    let mut labels: Vec<String> = Vec::new();
    opt_conf.with_value(|opt_conf| {
        if let Some(opts) = opt_conf {
            match opts {
                Options::Array(items) => {
                    items.iter().for_each(|item| {
                        if values.contains(&item.to_string()) {
                            labels.push(item.to_string());
                        }
                    });
                }
                Options::Map(kv_items) => {
                    kv_items.iter().for_each(|kv| {
                        if values.contains(&kv.value) {
                            labels.push(kv.label.clone());
                        }
                    });
                }
                Options::Tree(tree_nodes) => {
                    tree_nodes.iter().for_each(|node| {
                        if values.contains(&node.key) {
                            labels.push(node.title.clone());
                        }
                    });
                }
                Options::Fetch(_fetch_params) => {}
            };
        }
    });
    if labels.is_empty() {
        None
    } else {
        Some(labels.join("|"))
    }
}

fn get_multi_values(val: &Value) -> Vec<String> {
    let mut vals: Vec<String> = Vec::new();
    if val.is_array() {
        let val2 = val.as_array().unwrap();
        val2.iter().for_each(|v| {
            vals.push(v.to_string());
        })
    } else if val.is_string() {
        let val2 = val.as_str().unwrap();
        val2.split('|').into_iter().for_each(|v| {
            vals.push(v.to_string());
        })
    }
    vals
}
